
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;


import processing.core.PApplet;
import processing.core.PFont;
import processing.xml.XMLElement;


public class GLOBAL {

	// Connection to the database
	public static Connection user_db_con;
	public static Connection user_times_con;
	
	// Show info
	public static boolean show_info = false;

	// Map
	public static Map mapClass;

	// Screen Areas
	public static InfoPanel infoPanel;
	public static SelectionPanel selectionPanel;
	public static MultistatePanel multistatePanel;
	public static MapArea mapArea;
	public static GraphsArea graphsArea;
	public static ChartsArea chartsArea;
	public static SongsArea songsArea;

	// Parsed vars
	public static ArrayList<Continent> allContinents = new ArrayList<Continent>();
	public static final ArrayList<Nationality> allNationalities = new ArrayList<Nationality>();
	public static HashMap<String, Nationality> map_allNationalities = new HashMap<String, Nationality>();

	// Selection vars
	
	public static ArrayList<Nationality> nationalitiesSelected = new ArrayList<Nationality>(); // selected nationalities
	public static HashMap<String,Nationality> hashMapNationalitiesSelected = new HashMap<String,Nationality>(); // selected nationalities
	public static ArrayList<CloseButtonNationality> nationalitiesButtonSelected = new ArrayList<CloseButtonNationality>();
	public static ArrayList<Artist> artistsSelected = new ArrayList<Artist>();
	public static ArrayList<Person> personsSelected = new ArrayList<Person>();
	public static ArrayList<Group> groupsSelected = new ArrayList<Group>();
	public static boolean age_undefinedSelected = true;

	// Artist Info Buttons
	public static ArrayList<ButtonPlusMinusArtist> artistsInfoButtonSelected = new ArrayList<ButtonPlusMinusArtist>();
	public static ArrayList<ButtonPlusMinusArtist> personsInfoButtonSelected = new ArrayList<ButtonPlusMinusArtist>();
	public static ArrayList<ButtonPlusMinusArtist> groupsInfoButtonSelected = new ArrayList<ButtonPlusMinusArtist>();

	public static int ageStart, ageEnd;

	public static int genderSelected = 0; // 0=all, 1=M, 2=F
	public static int updateFilterResultsCalled = 0;

	public static int width=1024,height=720;
	public static PFont plotBoldFont;
	public static PFont plotFont;
	public static PFont newFont;
	public static GradientUtils gu;
	public static PApplet processing;
	public static int textColor = 224;
	public static int textBoldColor = 160;
	public static int textArtistNameColor = 224;
	public static int timer;

	//graph network data
	public static HashMap<Artist,ArrayList<Artist>> affineArtists = new HashMap<Artist,ArrayList<Artist>>();
	public static ArrayList<Artist> affineArtistsToShow = new ArrayList<Artist>();

	
	// Songs area vars
	public static ArrayList<Song> songsSelected = new ArrayList<Song>(); // selected songs
	public static ArrayList<CloseButtonSong> removeSongsSelected = new ArrayList<CloseButtonSong>(); // selected songs



	// Color
	public static int[] colors;
	public static int colorLines = 128;		
	public static int colorBackground = 35;
	public static int colorChartBackground = 30;
	public static int menuColor;
	public static ColorSwatch COLORS;

	// Use continent color if selected more then 10 (?)
	public static boolean continents_colors = false;

	// Artist threads active
	public static int artistsThreadsActive;

	
	// Charts vars
	public static ArrayList<String> lastfm_TopArtistsNames = new ArrayList<String>();
	public static ArrayList<String> lastfm_TopArtistsIDs = new ArrayList<String>();
	public static ArrayList<Integer> lastfm_TopArtistsPlayCount = new ArrayList<Integer>();
	public static ArrayList<Integer> lastfm_TopArtistsListeners = new ArrayList<Integer>();
	public static int lastfm_index_start=0;
	public static HashMap<String, ValueMap> charts_nPlaysPerArtist = new HashMap<String, ValueMap>();
	public static HashMap<String, ValueMap> charts_nPlaysPerArtist_sorted = new HashMap<String, ValueMap>();
	public static int topArtists_index_start=0;

	public static Object[] charts_nPlaysPerArtist_sortedSaved = null;
	public static int savedChart_index_start=0;
	
	public static int totalUsersSaved = 0;
	public static int totalUsersResult = 0;


	// Map vars
	// Num of plays per each hour per each nationality
	public static HashMap<Nationality, ArrayList<Float> > map_nPerHourPerNationality = new HashMap<Nationality, ArrayList<Float>>();
	public static HashMap<Continent, ArrayList<Float>> map_nPerHourPerContinent = new HashMap<Continent, ArrayList<Float>>();
	public static HashMap<Nationality, Integer> map_usersPerNationality = new HashMap<Nationality, Integer>();
	public static HashMap<Continent, Integer> map_usersPerContinent = new HashMap<Continent, Integer>();

	// Type of analysis
	public static int analysisType = 0; // 0 = charts, 1 = map, 2 = graph, 3 = song

	public static void nationalityAddAll(){
		for(int i=0;i<GLOBAL.allNationalities.size();i++){
			Nationality n = GLOBAL.allNationalities.get(i);
			if(!GLOBAL.nationalitiesSelected.contains(n)){
				// Assign color to nationality
				n.color = GLOBAL.COLORS.getColor(GLOBAL.nationalitiesSelected.size()%GLOBAL.COLORS.getArray().length);

				GLOBAL.nationalitiesSelected.add(n);
				GLOBAL.hashMapNationalitiesSelected.put(n.getName(),n);
				GLOBAL.nationalitiesButtonSelected.add(new CloseButtonNationality(n));


			}
		}
		if(GLOBAL.chartsArea.topArtist_chart != null){
			GLOBAL.chartsArea.topArtist_chart.maxYValue = 60;
			GLOBAL.chartsArea.topArtist_chart.verticalMaxInterval = 60/5;
			GLOBAL.chartsArea.topArtist_chart.verticalMinInterval = 60/20;
		}
		if(GLOBAL.nationalitiesSelected.size()>10)
			GLOBAL.continents_colors = true;
		else GLOBAL.continents_colors = false;

		GLOBAL.updateFilterResults();
	}

	public static void nationalityRemoveAll(){
		for(int i=GLOBAL.nationalitiesSelected.size()-1;i>0;i--){
			GLOBAL.nationalitiesButtonSelected.remove(i);
			GLOBAL.hashMapNationalitiesSelected.remove(GLOBAL.nationalitiesSelected.get(i).getName());
		}
		for(int i=GLOBAL.nationalitiesSelected.size()-1;i>0;i--){
			GLOBAL.nationalitiesSelected.remove(i); 
		}
		if(GLOBAL.chartsArea.thread.isAlive()) GLOBAL.chartsArea.thread.interrupt();
		nationalityAddRemove(GLOBAL.nationalitiesSelected.get(0));


	}

	public static void nationalityAddRemove(Nationality n) {
		if(GLOBAL.nationalitiesSelected.contains(n)){
			GLOBAL.nationalitiesButtonSelected.remove(GLOBAL.nationalitiesSelected.indexOf(n));
			GLOBAL.hashMapNationalitiesSelected.remove(n.getName());
			GLOBAL.nationalitiesSelected.remove(n); 

			// Assign color to nationality
			for(int i=0;i<GLOBAL.nationalitiesSelected.size();i++){
				GLOBAL.nationalitiesSelected.get(i).color = 
						GLOBAL.COLORS.getColor(i%GLOBAL.COLORS.getArray().length);
			}


			//update line chart label values
			GLOBAL.mapArea.plotsPanel.chart.verticalMaxInterval = 6/3;
			GLOBAL.mapArea.plotsPanel.chart.verticalMinInterval = 6/6;
			GLOBAL.mapArea.plotsPanel.chart.maxYValue = 6;


			if(GLOBAL.chartsArea.topArtist_chart != null){
				GLOBAL.chartsArea.topArtist_chart.maxYValue = 60;
				GLOBAL.chartsArea.topArtist_chart.verticalMaxInterval = 60/5;
				GLOBAL.chartsArea.topArtist_chart.verticalMinInterval = 60/20;
			}

		}
		else{

			// Assign color to nationality
			n.color = GLOBAL.COLORS.getColor(GLOBAL.nationalitiesSelected.size()%GLOBAL.COLORS.getArray().length);

			GLOBAL.nationalitiesSelected.add(n);
			GLOBAL.hashMapNationalitiesSelected.put(n.getName(),n);
			GLOBAL.nationalitiesButtonSelected.add(new CloseButtonNationality(n));

			if(GLOBAL.chartsArea.topArtist_chart != null){
				GLOBAL.chartsArea.topArtist_chart.maxYValue = 60;
				GLOBAL.chartsArea.topArtist_chart.verticalMaxInterval = 60/5;
				GLOBAL.chartsArea.topArtist_chart.verticalMinInterval = 60/20;
			}

		}

		if(GLOBAL.nationalitiesSelected.size()>10)
			GLOBAL.continents_colors = true;
		else GLOBAL.continents_colors = false;

		if(GLOBAL.nationalitiesButtonSelected.size()==0)
			GLOBAL.totalUsersResult = 0;
		
		GLOBAL.updateFilterResults();
	}




	public static String getArtistType(String artistName) {
		String url = "http://musicbrainz.org/ws/2/artist/?query=artist:";
		XMLElement xml = new XMLElement(GLOBAL.processing,url+artistName);

		// Get artist type
		String artistType = xml.getChild("artist-list/artist").getString("type");
		//System.out.println(artistType);
		return artistType;
	}

	public static void artistAddRemove(Artist a) {
		if(GLOBAL.artistsSelected.contains(a)){
			GLOBAL.artistsSelected.remove(a); 
			for(int i=0;i<GLOBAL.artistsInfoButtonSelected.size();i++){
				if(GLOBAL.artistsInfoButtonSelected.get(i).artist.equals(a)){
					GLOBAL.artistsInfoButtonSelected.remove(i);
					break;
				}
			}
		}
		else if (GLOBAL.personsSelected.contains(a)){
			GLOBAL.personsSelected.remove(a);
			for(int i=0;i<GLOBAL.personsInfoButtonSelected.size();i++){
				if(GLOBAL.personsInfoButtonSelected.get(i).artist.equals(a)){
					GLOBAL.personsInfoButtonSelected.remove(i);
					break;
				}
			}

		}
		else if (GLOBAL.groupsSelected.contains(a)){
			GLOBAL.groupsSelected.remove(a);
			for(int i=0;i<GLOBAL.groupsInfoButtonSelected.size();i++){
				if(GLOBAL.groupsInfoButtonSelected.get(i).artist.equals(a)){
					GLOBAL.groupsInfoButtonSelected.remove(i);
					break;
				}
			}
		}
		else{
			Artist.addArtist(a.arid, a.arName);
		}	
	}


	public static void updateFilterResults(){
		updateFilterResultsCalled++;

		if (analysisType == 0)
			chartsArea.updateFiltersResults();
		else if (analysisType == 1)
			mapArea.updateFiltersResults();
//		else if (analysisType == 2)
//			songsArea.updateFiltersResults();

	}

	public static void updateMapFilterResults() {
		mapArea.updateFiltersResults();

	}

	public static void updateChartsFilterResults() {
		chartsArea.updateFiltersResults();

	}

	public static void saveChart(){
		if(GLOBAL.chartsArea.topArtist_chart.valueMaps==null)return;
		if(GLOBAL.chartsArea.topArtist_chart.valueMaps.length==0) return;
		GLOBAL.charts_nPlaysPerArtist_sortedSaved = GLOBAL.chartsArea.topArtist_chart.valueMaps;
		GLOBAL.totalUsersSaved = GLOBAL.totalUsersResult;
		chartsArea.updateCharts();
	}

	public static void clearChart(){
		GLOBAL.charts_nPlaysPerArtist_sortedSaved = null;
		GLOBAL.totalUsersSaved = 0;
		chartsArea.updateCharts();
	}

	// Bruco variables	
	static int leftVal = 0,rightVal =10;
	static final int maxRightVal = 50;
	static final int minRightVal = 10;
	static final int maxLeftVal = 40;
	static final int minLefttVal = 0;
	static int directionLeft=1, directionRight =1;

	// Loading animation "Il Bruco"
	public static void loadingFun(){

		GLOBAL.processing.stroke(120);
		GLOBAL.processing.fill(120);
		for(int i=leftVal; i<rightVal;i++){
			GLOBAL.processing.ellipse(i+200,697,10,10);
		}
		rightVal+= directionRight;
		if(rightVal>maxRightVal){
			rightVal = maxRightVal;
			leftVal+=directionLeft;
		}
		if(leftVal>maxLeftVal){
			directionLeft=-1;
			leftVal +=directionLeft;
		}
		if(leftVal < minLefttVal){
			leftVal = minLefttVal;
			directionLeft=1;
			directionRight=-1;
		}
		if(rightVal <minRightVal){
			directionLeft = 1;
			directionRight=1;
		}
	}



	// Loading circle variables
	public static float angleNationality = 0;
	public static float angleArtist = 0;

	// Loading circle function
	public static float loadingCircle(int centerX,int centerY,float angle){
		int step = 6;
		int radius=10;
		int circleDim =6;
		int color = 190;
		float rotationSpeed = (float)8.5;

		GLOBAL.processing.stroke(120);
		GLOBAL.processing.noStroke();

		GLOBAL.processing.fill(color,255);
		GLOBAL.processing.ellipse((float)(radius*Math.cos(angle)+centerX),
				(float)(radius*Math.sin(angle)+centerY),circleDim,circleDim);
		GLOBAL.processing.fill(color,147);
		GLOBAL.processing.ellipse((float)(radius*Math.cos(angle+Math.PI/step)+centerX),
				(float)(radius*Math.sin(angle+Math.PI/step)+centerY),circleDim,circleDim);
		GLOBAL.processing.fill(color,40);
		GLOBAL.processing.ellipse((float)(radius*Math.cos(angle+2*Math.PI/step)+centerX),
				(float)(radius*Math.sin(angle+2*Math.PI/step)+centerY),circleDim,circleDim);

		angle -= Math.PI/rotationSpeed;
		if(angle > Math.PI)
			angle = 0;

		return angle;

	}

	// Handles add and remove of artists to show in the graph
	public static void addRemoveArtistToGraph(Artist a) {
		int maxSize = 2;

		// If artist already in arraylist do nothing
		for(int i=0;i<affineArtistsToShow.size();i++){
			if(a.arid.equalsIgnoreCase(affineArtistsToShow.get(i).arid))
				return;
		}
		
		// If size exceeds maxSize error
		if (affineArtistsToShow.size()>maxSize){
			System.out.println("Something went wrong GLOBAL.addRemoveArtistToGraph");
			return;
		}
		// If artist size == maxSize then sustitute the first with the new artist
		if(GLOBAL.affineArtistsToShow.size()==maxSize){
			GLOBAL.affineArtistsToShow.set(0, GLOBAL.affineArtistsToShow.get(1));
			GLOBAL.affineArtistsToShow.set(1, a);
		}
		// else add the new artist
		else if (GLOBAL.affineArtistsToShow.size()<maxSize){
			GLOBAL.affineArtistsToShow.add(a);
		}
		
//		for(int i=0;i<affineArtistsToShow.size();i++){
//			System.out.println(affineArtistsToShow.get(i).arName);
//		}
		
		GLOBAL.graphsArea.networkGraph.loadData();
	}

	// Add/Remove a song from those selected
	public static void songAddRemove(Song s) {

		// If contained remove the song from those selected
		if(GLOBAL.songsSelected.contains(s)){
			for(int i=0;i<GLOBAL.removeSongsSelected.size();i++){
				if(s.equals(GLOBAL.removeSongsSelected.get(i).song))
					GLOBAL.removeSongsSelected.remove(i);
			}
			songsSelected.remove(s);
			GLOBAL.songsArea.songsSelected.updateValues();
			songsArea.changeTagCloud();
			songsArea.tagCloud.updateTagCloud();
		}
		// If not contained add the song to those selected
		else {
			Song.addSong(s.title,s.artistName);
		}
		
		
	}

}
